/**
 * This implements the user loginData for Hollyweb.
 * @module
 */

/*
 * The sessionStorage stores the following private information about current login session
 * loginData: {loggedIn: true or false, indicates whether user is logged in,
 *             id: the user id,
 *             fullName: the user full name,
 *             portrait: the user portrait,
 *             interface: {colorSelect, darkMode},
 *             security: {isAdmin, adminLevel, adminPermission}}
 *
 * The localStorage stores some temporary data
 * searchWord: cached search bar input
 */

// import from packages
import localforage from "localforage";

// local imports
import {
  saveToSession,
  getFromSession,
  saveToStorage,
  getFromStorage,
  removeFromSession,
  removeFromStorage,
  clearSession
} from "../localCache/lilyLocalCache";
import { HOST_NAME_PORT } from "../lib/constants";
import { joinURL } from "../components/common/utilities";
import apiClient from "./apiClient";
import { setSearchForm } from "../localCache/searchCache";
/* -------------------------------------------
 *              set/get LoginData
 * -------------------------------------------*/

/**
 * Save loginData in session or storage
 */
const SAVE_LOGIN_IN_SESSION = false;

/**
 * Save loginData into sesion or storage
 * @param {object} loginData
 */
export function setLoginData(loginData) {
  if (SAVE_LOGIN_IN_SESSION) {
    saveToSession("loginData", loginData);
  } else {
    saveToStorage("loginData", loginData);
  }
}

/**
 * Get loginData from sesion or storage
 * @return {object} loginData
 */
export function getLoginData() {
  let loginData;
  if (SAVE_LOGIN_IN_SESSION) {
    loginData = getFromSession("loginData");
  } else {
    loginData = getFromStorage("loginData");
  }

  return loginData;
}

/**
 * Clear loginData
 */
export function clearLoginData() {
  if (SAVE_LOGIN_IN_SESSION) {
    removeFromSession("loginData");
  } else {
    removeFromStorage("loginData");
  }
}

/* -------------------------------------------
 *               LoginData APIs
 * -------------------------------------------*/

/**
 * Get user login status
 * @returns {boolean} true if logged in, false otherwise
 */
export function loginStatus() {
  // dig out login info from sessionStorage
  const loginData = getLoginData();
  return loginData?.loggedIn === true;
}

/**
 * Get user NickName
 */
export function loginNickName() {
  // dig out login info from sessionStorage
  const loginData = getLoginData();
  return loginData?.nickName;
}
/**
 * Get user's login id
 * @returns {string} user's id if loggedIn, undefined otherwise
 */
export function loginId() {
  // dig out login info from sessionStorage
  const loginData = getLoginData();
  return loginData?.id;
}

/**
 * Get user portrait location
 * @returns user portrait location
 */
export function getPortrait() {
  // dig out login info from sessionStorage
  const loginData = getLoginData();
  return loginData?.portrait;
}

/**
 * Update the portrait information in loginData
 * @param {string} portrait - location of user portrait
 */
export function updatePortrait(portrait) {
  const loginData = getLoginData();
  loginData.portrait = portrait;
  setLoginData(loginData);
}

/**
 * Update loginData based on new peopleEdit info
 * @param {*} peopleEdit
 */
export function updateLoginDataAfterPeopleEdit(peopleEdit) {
  const loginData = getLoginData();
  if (peopleEdit.fullName) {
    loginData.fullName = peopleEdit.fullName;
  }
  if (peopleEdit.portrait) {
    loginData.portrait = peopleEdit.portrait;
  }
  if (peopleEdit.security) {
    loginData.security = peopleEdit.security;
  }
  setLoginData(loginData);
}

/**
 * Get user selected color from sessionStorage.
 * @returns {number} colorSelect, default to 0
 */
export function getColorSelect() {
  const loginData = getLoginData();
  return loginData?.interface?.colorSelect || 0;
}

/**
 * Get user preferred dark/light mode from sessionStorage.
 * @returns {boolean} darkMode, default to false
 */
export function getDarkMode() {
  const loginData = getLoginData();
  return loginData?.interface?.darkMode === true;
}


/**
 * Get admin information
 * @returns {object} admin info, an object containing the following information
 *                   - isAdmin: {Boolean}
 *                   - adminLevel: {Number} 0 (not admin), 100 (local admin), 200 (global admin)
 *                   - adminPermission: {Array.<id>} array of department ids
 */
export function getAdminInfo() {
  const loginData = getLoginData();
  return loginData?.security;
}

/* -------------------------------------------
 *                Local cache
 * -------------------------------------------*/

/**
 * Get cached searchWord in search input, this might be used by multiple search inputs
 * @returns {string} searchWord, the input search word
 */
export function getSearchWord() {
  return getFromSession("searchWord") || "";
}

/**
 * Cache searchWord in navigation drawer's search input
 * @param {string} searchWord - the search word in search input
 */
export function updateSearchWord(searchWord = "") {
  saveToSession("searchWord", searchWord);
}

/**
 * Save a message draft
 * @param {object} draft - {title, content, receiverIds, priority}
 */
export function saveDraftMessage(draft) {
  saveToSession("draftMessage", draft);
}

/**
 * Get the message draft
 * @returns {object} draft - {title, content, receiverIds, priority}
 */
export function getDraftMessage() {
  return getFromSession("draftMessage");
}

/**
 * Delete the message draft
 * @returns {object} draft - {title, content, receiverIds, priority}
 */
export function deleteDraftMessage() {
  return removeFromSession("draftMessage");
}

/**
 * Is the message draft empty?
 * @returns {object} draft - {title, content, receiverIds, priority}
 */
export function isDraftMessageEmpty() {
  const draft = getDraftMessage();
  return draft === null || draft === undefined;
}

/* -------------------------------------------
 *               Clear cache
 * -------------------------------------------*/

/**
 * Clear all local forage data
 */
export async function clearLocalForage() {
  // This clears everything in localforage
  await localforage.clear();
}

/**
 * Clear all local cache data
 */
export async function clearLocalCache() {
  // This clears everything in localforage
  await localforage.clear();
  localStorage.clear();
  sessionStorage.clear();
}
/* -------------------------------------------
 *                
 * -------------------------------------------*/
/**
 * Initialize local cache at login or cache refresh
 * *** Read this before you change any code here ***
 * The order of data structure initialization is important.
 * 1) peopleListMap should init after departmentMap init since it needs departmentName
 * 2) savePersonToMap shoulld happen after peopleMap init since it need peopleMap
 * 3) savePersonToMap should happen after userGroups init since it removes group info
 * 4) userMessages should init after userModels init since it uses peopleListMap
 * @param {*} userInfo - user information object
 * @throw error as it will attempt server connection
 */
export async function initUserCache(userInfo) {
  if (userInfo) {
    const loginData = {
      loggedIn: true,
      id: userInfo.id,
      nickName: userInfo.nickname,
      interface: userInfo.interface,
    };
    setLoginData(loginData);
    //TODO先设置为null
    await setSearchForm(null);
  }
}

/**
 * Refresh local cache
 * @return {string} error message
 */
export async function refreshLocalCache() {
  try {
    // Reload data from server
    // Has to do this before clear cache in case server connection fails
    const url = joinURL(HOST_NAME_PORT, `user/info`);
    const response = await apiClient.get(url);
    const userInfo = response.data;
    if (userInfo) {
      // We clear session and localforage only if connection is successful
      clearSession();
      await clearLocalForage();
      //TODO 清除了 缓存，导致提交表单为空，这里要重新设计逻辑

      await initUserCache(userInfo);
      return "";
    }
  } catch (err) {
    // do nothing
    return "刷新缓存失败，请检查您的网络连接。";
  }
  return "刷新缓存失败。";
}

/**
 * Update user preferred dark/light mode, and synch with the server
 * @param {boolean} newDarkMode new dark mode
 * @return {string} error message
 */
export async function updateDarkMode(newDarkMode = false) {
  // Get loginData from localStorage
  const loginData = getLoginData() || {};
  if (loginData.interface?.darkMode !== newDarkMode) {
    loginData.interface = loginData.interface || {};

    // update local cache
    loginData.interface.darkMode = newDarkMode;
    setLoginData(loginData);

    // Update the color select at server
    const url = joinURL(HOST_NAME_PORT, "user/interface");
    try {
      await apiClient.post(url, loginData.interface);
    } catch (err) {
      return "无法连接服务器。";
    }
  }
  return "";
}